--[[
CastYeller2 - Announce important spell events.

Copyright (C) 2009 Adirelle

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
--]]

if not CastYeller2 then return end
local CastYeller2 = CastYeller2 
local L = CastYeller2.L

local mod, super = CastYeller2:NewSourceModule('Cooldowns', 'AceEvent-3.0', 'AceTimer-3.0')

mod.moduleTitle = L['Cooldowns']

mod.triggers = {
	cooldownStart = L['Cooldown start'],
	cooldownEnd = L['Cooldown end'],
}

mod.defaultAnnounces = {
	cooldownStart = L['$SPELL is in cooldown[ ${DURATION}]'],
	cooldownEnd = L['$SPELL is ready'],
}

local pName = UnitName('player')

local cooldowns = {}
local lastCastTime = {}
local timer

function mod:OnEnable()
	super.OnEnable(self)
	self:RegisterEvent('SPELL_UPDATE_COOLDOWN', 'EarlyCheck')
	self:RegisterEvent('PET_BAR_UPDATE_COOLDOWN', 'EarlyCheck')
	self:RegisterEvent('BAG_UPDATE_COOLDOWN', 'EarlyCheck')
	self:RegisterEvent('UNIT_SPELLCAST_SENT')
	self:RegisterEvent('UNIT_SPELLCAST_STOP', 'UNIT_SPELLCAST_SENT')
	self:RegisterEvent('UNIT_SPELLCAST_CHANNEL_STOP', 'UNIT_SPELLCAST_SENT')
end

function mod:OnDisable()
	super.OnDisable(self)
	wipe(cooldowns)
	wipe(lastCastTime)
end

function mod:UNIT_SPELLCAST_SENT(_, unit, spell)
	if unit == 'player' and self:IsNameWatched(spell) then
		lastCastTime[spell] = GetTime()
		self:EarlyCheck()
	end
end

function mod:EarlyCheck()
	if timer then
		self:CancelTimer(timer, true)
		timer = nil
	end
	timer = self:ScheduleTimer('CheckCooldowns', 0.1)
end

local function GetCooldown(name, now)
	local start, duration, enabled
	if name:find('[()]') then
		start, duration, enabled = GetSpellCooldown(name..'()')
	else
		start, duration, enabled = GetSpellCooldown(name)
	end
	if not enabled and not start then
		start, duration, enabled = GetItemCooldown(name)
	end
	if enabled and start + duration > now and duration > 1.5 then
		return start + duration, duration
	end
	return nil
end

function mod:CheckCooldowns()
	local now = GetTime()
	for name, oldEndTime in pairs(cooldowns) do
		local endTime = GetCooldown(name, now)
		if not endTime or endTime < now then
			self:TriggerAnnounce('cooldownEnd', pName, name)
			cooldowns[name] = nil
		else
			cooldowns[name] = endTime
		end
	end
	for name, castTime in pairs(lastCastTime) do
		if now - castTime > 3 then
			lastCastTime[name] = nil
		else
			local endTime, duration = GetCooldown(name, now)
			if endTime and not cooldowns[name] then
				self:TriggerAnnounce('cooldownStart', pName, name, duration)				
				cooldowns[name] = endTime
				lastCastTime[name] = nil
			end
		end
	end
	if timer then
		self:CancelTimer(timer, true)
		timer = nil
	end
	if next(cooldowns) or next(lastCastTime) then
		timer = self:ScheduleTimer('CheckCooldowns', 1)
	end
end

